﻿using EventBus.Abstractions;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EventBus
{
    /// <summary>
    /// Event execution context.
    /// </summary>
    public class EventHandlerExecutionContext
        : IEventHandlerExecutionContext
    {
        private readonly IServiceProvider _sp;
        private readonly IServiceCollection _services;
        private readonly ConcurrentDictionary<Type, List<Type>> _registrations = new ConcurrentDictionary<Type, List<Type>>();
        public EventHandlerExecutionContext(IServiceCollection services)
        {
            _services = services;
            _sp = services.BuildServiceProvider();
        }


        public async Task HandleAsync<TEvent>(TEvent @event) where TEvent : IEvent
        {
            if (_registrations.TryGetValue(typeof(TEvent), out var types))
            {
                if (types != null && types.Any())
                {
                    using (var scope = _sp.CreateScope())
                    {
                        foreach (var type in types)
                        {
                            var handler = Activator.CreateInstance(type) as IEventHandler;
                            await handler.HandleAsync(@event);
                        }
                    }
                }
            }
        }


        public bool IsRegisteEventHandler<TEvent, TEventHandler>()
            where TEvent : IEvent
            where TEventHandler : IEventHandler
        {
            if (_registrations.TryGetValue(typeof(TEvent), out var types))
            {
                return types != null && types.Contains(typeof(TEventHandler));
            }
            return false;
        }


        public void RegisteEventHandler<TEvent, TEventHandler>()
            where TEvent : IEvent
            where TEventHandler : IEventHandler
        {
            if (_registrations.TryGetValue(typeof(TEvent), out var types))
            {
                if (types != null)
                {
                    if (!types.Contains(typeof(TEventHandler)))
                    {
                        types.Add(typeof(TEventHandler));
                    }
                }
                else
                {
                    _registrations[typeof(TEvent)] = new List<Type>() { typeof(TEventHandler) };
                }
            }
            else
            {
                _registrations.TryAdd(typeof(TEvent), new List<Type>() { typeof(TEventHandler) });
            }
        }
    }
}
